﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace LibNoise.Utilities {
	/// Renders an image from a noise map.
	///
	/// This class renders an image given the contents of a noise-map object.
	///
	/// An application can configure the output of the image in three ways:
	/// - Specify the color gradient.
	/// - Specify the light source parameters.
	/// - Specify the background image.
	///
	/// <b>Specify the color gradient</b>
	///
	/// This class uses a color gradient to calculate the color for each pixel
	/// in the destination image according to the value from the corresponding
	/// position in the noise map.
	///
	/// A color gradient is a list of gradually-changing colors.  A color
	/// gradient is defined by a list of <i>gradient points</i>.  Each
	/// gradient point has a position and a color.  In a color gradient, the
	/// colors between two adjacent gradient points are linearly interpolated.
	///
	/// For example, suppose this class contains the following color gradient:
	///
	/// - -1.0 maps to dark blue.
	/// - -0.2 maps to light blue.
	/// - -0.1 maps to tan.
	/// - 0.0 maps to green.
	/// - 1.0 maps to white.
	///
	/// The value 0.5 maps to a greenish-white color because 0.5 is halfway
	/// between 0.0 (mapped to green) and 1.0 (mapped to white).
	///
	/// The value -0.6 maps to a medium blue color because -0.6 is halfway
	/// between -1.0 (mapped to dark blue) and -0.2 (mapped to light blue).
	///
	/// The color gradient requires a minimum of two gradient points.
	///
	/// This class contains two pre-made gradients: a grayscale gradient and a
	/// color gradient suitable for terrain.  To use these pre-made gradients,
	/// call the BuildGrayscaleGradient() or BuildTerrainGradient() methods,
	/// respectively.
	///
	/// @note The color value passed to AddGradientPoint() has an alpha
	/// channel.  This alpha channel specifies how a pixel in the background
	/// image (if specified) is blended with the calculated color.  If the
	/// alpha value is high, this class weighs the blend towards the
	/// calculated color, and if the alpha value is low, this class weighs the
	/// blend towards the color from the corresponding pixel in the background
	/// image.
	///
	/// <b>Specify the light source parameters</b>
	///
	/// This class contains a parallel light source that lights the image.  It
	/// interprets the noise map as a bump map.
	///
	/// To enable or disable lighting, pass a Boolean value to the
	/// EnableLight() method.
	///
	/// To set the position of the light source in the "sky", call the
	/// SetLightAzimuth() and SetLightElev() methods.
	///
	/// To set the color of the light source, call the SetLightColor() method.
	///
	/// To set the intensity of the light source, call the SetLightIntensity()
	/// method.  A good intensity value is 2.0, although that value tends to
	/// "wash out" very light colors from the image.
	/// 
	/// To set the contrast amount between areas in light and areas in shadow,
	/// call the SetLightContrast() method.  Determining the correct contrast
	/// amount requires some trial and error, but if your application
	/// interprets the noise map as a height map that has its elevation values
	/// measured in meters and has a horizontal resolution of @a h meters, a
	/// good contrast amount to use is ( 1.0 / @a h ).
	/// 
	/// <b>Specify the background image</b>
	///
	/// To specify a background image, pass an Image object to the
	/// SetBackgroundImage() method.
	///
	/// This class determines the color of a pixel in the destination image by
	/// blending the calculated color with the color of the corresponding
	/// pixel from the background image.
	///
	/// The blend amount is determined by the alpha of the calculated color.
	/// If the alpha value is high, this class weighs the blend towards the
	/// calculated color, and if the alpha value is low, this class weighs the
	/// blend towards the color from the corresponding pixel in the background
	/// image.
	///
	/// <b>Rendering the image</b>
	///
	/// To render the image, perform the following steps:
	/// - Pass a NoiseMap object to the SetSourceNoiseMap() method.
	/// - Pass an Image object to the SetDestImage() method.
	/// - Pass an Image object to the SetBackgroundImage() method (optional)
	/// - Call the Render() method.
	public class RendererImage {
		/// Constructor.
		public RendererImage() {
			m_isLightEnabled = false;
			m_isWrapEnabled = false;
			m_lightAzimuth = 45.0;
			m_lightBrightness = 1.0;
			m_lightColor = System.Drawing.Color.FromArgb(255, 255, 255, 255);
			m_lightContrast = 1.0;
			m_lightElev = 45.0;
			m_lightIntensity = 1.0;
			m_pBackgroundImage = null;
			m_pSourceNoiseMap = null;
			m_recalcLightValues = true;
			BuildGrayscaleGradient();
		}

		/// Adds a gradient point to this gradient object.
		///
		/// @param gradientPos The position of this gradient point.
		/// @param gradientColor The color of this gradient point.
		///
		/// @pre No two gradient points have the same position.
		///
		/// @throw noise::ExceptionInvalidParam See the preconditions.
		///
		/// This object uses a color gradient to calculate the color for each
		/// pixel in the destination image according to the value from the
		/// corresponding position in the noise map.
		///
		/// The gradient requires a minimum of two gradient points.
		///
		/// The specified color value passed to this method has an alpha
		/// channel.  This alpha channel specifies how a pixel in the
		/// background image (if specified) is blended with the calculated
		/// color.  If the alpha value is high, this object weighs the blend
		/// towards the calculated color, and if the alpha value is low, this
		/// object weighs the blend towards the color from the corresponding
		/// pixel in the background image.
		public void AddGradientPoint(double gradientPos, System.Drawing.Color gradientColor) {
			m_gradient.AddGradientPoint(gradientPos, gradientColor);
		}

		/// Builds a grayscale gradient.
		///
		/// @post The original gradient is cleared and a grayscale gradient is
		/// created.
		///
		/// This color gradient contains the following gradient points:
		/// - -1.0 maps to black
		/// - 1.0 maps to white
		public void BuildGrayscaleGradient() {
			ClearGradient();
			m_gradient.AddGradientPoint(-1.0, System.Drawing.Color.FromArgb(255, 0, 0, 0));
			m_gradient.AddGradientPoint(1.0, System.Drawing.Color.FromArgb(255, 255, 255, 255));
		}

		/// Builds a color gradient suitable for terrain.
		///
		/// @post The original gradient is cleared and a terrain gradient is
		/// created.
		///
		/// This gradient color at position 0.0 is the "sea level".  Above
		/// that value, the gradient contains greens, browns, and whites.
		/// Below that value, the gradient contains various shades of blue.
		public void BuildTerrainGradient() {
			ClearGradient();
			m_gradient.AddGradientPoint(-1.00, System.Drawing.Color.FromArgb(255, 0, 0, 128));
			m_gradient.AddGradientPoint(-0.20, System.Drawing.Color.FromArgb(255, 32, 64, 128));
			m_gradient.AddGradientPoint(-0.04, System.Drawing.Color.FromArgb(255, 64, 96, 192));
			m_gradient.AddGradientPoint(-0.02, System.Drawing.Color.FromArgb(255, 192, 192, 128));
			m_gradient.AddGradientPoint(0.00, System.Drawing.Color.FromArgb(255, 0, 192, 0));
			m_gradient.AddGradientPoint(0.25, System.Drawing.Color.FromArgb(255, 192, 192, 0));
			m_gradient.AddGradientPoint(0.50, System.Drawing.Color.FromArgb(255, 160, 96, 64));
			m_gradient.AddGradientPoint(0.75, System.Drawing.Color.FromArgb(255, 128, 255, 255));
			m_gradient.AddGradientPoint(1.00, System.Drawing.Color.FromArgb(255, 255, 255, 255));
		}

		/// Clears the color gradient.
		///
		/// Before calling the Render() method, the application must specify a
		/// new color gradient with at least two gradient points.
		public void ClearGradient() {
			if (m_gradient == null) {
				m_gradient = new GradientColor();
			}
			m_gradient.Clear();
		}

		/// Enables or disables the light source.
		///
		/// @param enable A flag that enables or disables the light source.
		///
		/// If the light source is enabled, this object will interpret the
		/// noise map as a bump map.
		public void EnableLight(bool enable = true) {
			m_isLightEnabled = enable;
		}

		/// Enables or disables noise-map wrapping.
		///
		/// @param enable A flag that enables or disables noise-map wrapping.
		///
		/// This object requires five points (the initial point and its four
		/// neighbors) to calculate light shading.  If wrapping is enabled,
		/// and the initial point is on the edge of the noise map, the
		/// appropriate neighbors that lie outside of the noise map will
		/// "wrap" to the opposite side(s) of the noise map.  Otherwise, the
		/// appropriate neighbors are cropped to the edge of the noise map.
		///
		/// Enabling wrapping is useful when creating spherical renderings and
		/// tileable textures.
		public void EnableWrap(bool enable = true) {
			m_isWrapEnabled = enable;
		}

		/// Returns the azimuth of the light source, in degrees.
		///
		/// @returns The azimuth of the light source.
		///
		/// The azimuth is the location of the light source around the
		/// horizon:
		/// - 0.0 degrees is east.
		/// - 90.0 degrees is north.
		/// - 180.0 degrees is west.
		/// - 270.0 degrees is south.
		public double GetLightAzimuth() {
			return m_lightAzimuth;
		}

		/// Returns the brightness of the light source.
		///
		/// @returns The brightness of the light source.
		public double GetLightBrightness() {
			return m_lightBrightness;
		}

		/// Returns the color of the light source.
		///
		/// @returns The color of the light source.
		public System.Drawing.Color GetLightColor() {
			return m_lightColor;
		}

		/// Returns the contrast of the light source.
		///
		/// @returns The contrast of the light source.
		///
		/// The contrast specifies how sharp the boundary is between the
		/// light-facing areas and the shadowed areas.
		///
		/// The contrast determines the difference between areas in light and
		/// areas in shadow.  Determining the correct contrast amount requires
		/// some trial and error, but if your application interprets the noise
		/// map as a height map that has a spatial resolution of @a h meters
		/// and an elevation resolution of 1 meter, a good contrast amount to
		/// use is ( 1.0 / @a h ).
		public double GetLightContrast() {
			return m_lightContrast;
		}

		/// Returns the elevation of the light source, in degrees.
		///
		/// @returns The elevation of the light source.
		///
		/// The elevation is the angle above the horizon:
		/// - 0 degrees is on the horizon.
		/// - 90 degrees is straight up.
		public double GetLightElev() {
			return m_lightElev;
		}

		/// Returns the intensity of the light source.
		///
		/// @returns The intensity of the light source.
		public double GetLightIntensity() {
			return m_lightIntensity;
		}

		/// Determines if the light source is enabled.
		///
		/// @returns
		/// - @a true if the light source is enabled.
		/// - @a false if the light source is disabled.
		public bool IsLightEnabled() {
			return m_isLightEnabled;
		}

		/// Determines if noise-map wrapping is enabled.
		///
		/// @returns
		/// - @a true if noise-map wrapping is enabled.
		/// - @a false if noise-map wrapping is disabled.
		///
		/// This object requires five points (the initial point and its four
		/// neighbors) to calculate light shading.  If wrapping is enabled,
		/// and the initial point is on the edge of the noise map, the
		/// appropriate neighbors that lie outside of the noise map will
		/// "wrap" to the opposite side(s) of the noise map.  Otherwise, the
		/// appropriate neighbors are cropped to the edge of the noise map.
		///
		/// Enabling wrapping is useful when creating spherical renderings and
		/// tileable textures
		public bool IsWrapEnabled() {
			return m_isWrapEnabled;
		}

		/// Renders the destination image using the contents of the source
		/// noise map and an optional background image.
		///
		/// @pre SetSourceNoiseMap() has been previously called.
		/// @pre SetDestImage() has been previously called.
		/// @pre There are at least two gradient points in the color gradient.
		/// @pre No two gradient points have the same position.
		/// @pre If a background image was specified, it has the exact same
		/// size as the source height map.
		///
		/// @post The original contents of the destination image is destroyed.
		///
		/// @throw noise::ExceptionInvalidParam See the preconditions.
		///
		/// The background image and the destination image can safely refer to
		/// the same image, although in this case, the destination image is
		/// irretrievably blended into the background image.
		public Bitmap Render() {

			if (m_pSourceNoiseMap == null || m_pSourceNoiseMap.GetWidth() <= 0
					|| m_pSourceNoiseMap.GetHeight() <= 0 || m_gradient.GetGradientPointCount() < 2) {
				throw new Exception("Invalid Parameter");
			}

			Bitmap m_pDestImage = null;

			int width = m_pSourceNoiseMap.GetWidth();
			int height = m_pSourceNoiseMap.GetHeight();

			// If a background image was provided, make sure it is the same size the
			// source noise map.
			if (m_pBackgroundImage != null) {
				if (m_pBackgroundImage.Width != width || m_pBackgroundImage.Height != height) {
					throw new Exception("Invalid Parameter");
				}
			}

			// Create the destination image.  It is safe to reuse it if this is also the
			// background image.
			//if (m_pDestImage != m_pBackgroundImage) {
				m_pDestImage = new Bitmap(width, height);
			//}

			for (int y = 0; y < height; y++) {
				System.Drawing.Color pBackground = Color.White;
				for (int x = 0; x < width; x++) {
					float pSource = m_pSourceNoiseMap.GetConstSlabPtr(x, y);
					Color pDest = m_pDestImage.GetPixel(x, y);
					if (m_pBackgroundImage != null) {
						pBackground = m_pBackgroundImage.GetPixel(x, y);
					}

					// Get the color based on the value at the current point in the noise
					// map.
					Color destColor = m_gradient.GetColor(pSource);

					// If lighting is enabled, calculate the light intensity based on the
					// rate of change at the current point in the noise map.
					double lightIntensity;
					if (m_isLightEnabled) {

						// Calculate the positions of the current point's four-neighbors.
						int xLeftOffset, xRightOffset;
						int yUpOffset, yDownOffset;
						if (m_isWrapEnabled) {
							if (x == 0) {
								xLeftOffset = (int)width - 1;
								xRightOffset = 1;
							} else if (x == (int)width - 1) {
								xLeftOffset = -1;
								xRightOffset = -((int)width - 1);
							} else {
								xLeftOffset = -1;
								xRightOffset = 1;
							}

							if (y == 0) {
								yDownOffset = (int)height - 1;
								yUpOffset = 1;
							} else if (y == (int)height - 1) {
								yDownOffset = -1;
								yUpOffset = -((int)height - 1);
							} else {
								yDownOffset = -1;
								yUpOffset = 1;
							}
						} else {
							if (x == 0) {
								xLeftOffset = 0;
								xRightOffset = 1;
							} else if (x == (int)width - 1) {
								xLeftOffset = -1;
								xRightOffset = 0;
							} else {
								xLeftOffset = -1;
								xRightOffset = 1;
							}
							if (y == 0) {
								yDownOffset = 0;
								yUpOffset = 1;
							} else if (y == (int)height - 1) {
								yDownOffset = -1;
								yUpOffset = 0;
							} else {
								yDownOffset = -1;
								yUpOffset = 1;
							}
						}
						//yDownOffset *= m_pSourceNoiseMap.GetStride();
						//yUpOffset   *= m_pSourceNoiseMap.GetStride();

						// Get the noise value of the current point in the source noise map
						// and the noise values of its four-neighbors.
						double nc = (double)(pSource);
						double nl = (double)((m_pSourceNoiseMap.GetConstSlabPtr(x + xLeftOffset, y)));
						double nr = (double)((m_pSourceNoiseMap.GetConstSlabPtr(x + xRightOffset, y)));
						double nd = (double)((m_pSourceNoiseMap.GetConstSlabPtr(x, y + yDownOffset)));
						double nu = (double)((m_pSourceNoiseMap.GetConstSlabPtr(x, y + yUpOffset)));

						// Now we can calculate the lighting intensity.
						lightIntensity = CalcLightIntensity(nc, nl, nr, nd, nu);
						lightIntensity *= m_lightBrightness;

					} else {

						// These values will apply no lighting to the destination image.
						lightIntensity = 1.0;
					}

					// Get the current background color from the background image.
					System.Drawing.Color backgroundColor = System.Drawing.Color.FromArgb(255, 255, 255, 255);
					if (m_pBackgroundImage != null) {
						backgroundColor = pBackground;
					}
					
					// Blend the destination color, background color, and the light
					// intensity together, then update the destination image with that
					// color.
					m_pDestImage.SetPixel(x, y, CalcDestColor(destColor, backgroundColor, lightIntensity));
				}
			}
			return m_pDestImage;
		}

		/// Sets the background image.
		///
		/// @param backgroundImage The background image.
		///
		/// If a background image has been specified, the Render() method
		/// blends the pixels from the background image onto the corresponding
		/// pixels in the destination image.  The blending weights are
		/// determined by the alpha channel in the pixels in the destination
		/// image.
		///
		/// The destination image must exist throughout the lifetime of this
		/// object unless another image replaces that image.
		public void SetBackgroundImage(Bitmap backgroundImage) {
			m_pBackgroundImage = backgroundImage;
		}

		/// Sets the azimuth of the light source, in degrees.
		///
		/// @param lightAzimuth The azimuth of the light source.
		///
		/// The azimuth is the location of the light source around the
		/// horizon:
		/// - 0.0 degrees is east.
		/// - 90.0 degrees is north.
		/// - 180.0 degrees is west.
		/// - 270.0 degrees is south.
		///
		/// Make sure the light source is enabled via a call to the
		/// EnableLight() method before calling the Render() method.
		public void SetLightAzimuth(double lightAzimuth) {
			m_lightAzimuth = lightAzimuth;
			m_recalcLightValues = true;
		}

		/// Sets the brightness of the light source.
		///
		/// @param lightBrightness The brightness of the light source.
		///
		/// Make sure the light source is enabled via a call to the
		/// EnableLight() method before calling the Render() method.
		public void SetLightBrightness(double lightBrightness) {
			m_lightBrightness = lightBrightness;
			m_recalcLightValues = true;
		}

		/// Sets the color of the light source.
		///
		/// @param lightColor The light color.
		///
		/// Make sure the light source is enabled via a call to the
		/// EnableLight() method before calling the Render() method.
		public void SetLightColor(System.Drawing.Color lightColor) {
			m_lightColor = lightColor;
		}

		/// Sets the contrast of the light source.
		///
		/// @param lightContrast The contrast of the light source.
		///
		/// @pre The specified light contrast is positive.
		///
		/// @throw noise::ExceptionInvalidParam See the preconditions.
		///
		/// The contrast specifies how sharp the boundary is between the
		/// light-facing areas and the shadowed areas.
		///
		/// The contrast determines the difference between areas in light and
		/// areas in shadow.  Determining the correct contrast amount requires
		/// some trial and error, but if your application interprets the noise
		/// map as a height map that has a spatial resolution of @a h meters
		/// and an elevation resolution of 1 meter, a good contrast amount to
		/// use is ( 1.0 / @a h ).
		///
		/// Make sure the light source is enabled via a call to the
		/// EnableLight() method before calling the Render() method.
		public void SetLightContrast(double lightContrast) {
			if (lightContrast <= 0.0) {
				throw new Exception("Invalid Parameter");
			}

			m_lightContrast = lightContrast;
			m_recalcLightValues = true;
		}

		/// Sets the elevation of the light source, in degrees.
		///
		/// @param lightElev The elevation of the light source.
		///
		/// The elevation is the angle above the horizon:
		/// - 0 degrees is on the horizon.
		/// - 90 degrees is straight up.
		///
		/// Make sure the light source is enabled via a call to the
		/// EnableLight() method before calling the Render() method.
		public void SetLightElev(double lightElev) {
			m_lightElev = lightElev;
			m_recalcLightValues = true;
		}

		/// Returns the intensity of the light source.
		///
		/// @returns The intensity of the light source.
		///
		/// A good value for intensity is 2.0.
		///
		/// Make sure the light source is enabled via a call to the
		/// EnableLight() method before calling the Render() method.
		public void SetLightIntensity(double lightIntensity) {
			if (lightIntensity < 0.0) {
				throw new Exception("Invalid Parameter");
			}

			m_lightIntensity = lightIntensity;
			m_recalcLightValues = true;
		}

		/// Sets the source noise map.
		///
		/// @param sourceNoiseMap The source noise map.
		///
		/// The destination image must exist throughout the lifetime of this
		/// object unless another image replaces that image.
		public void SetSourceNoiseMap(NoiseMap sourceNoiseMap) {
			m_pSourceNoiseMap = sourceNoiseMap;
		}

		/// Calculates the destination color.
		///
		/// @param sourceColor The source color generated from the color
		/// gradient.
		/// @param backgroundColor The color from the background image at the
		/// corresponding position.
		/// @param lightValue The intensity of the light at that position.
		///
		/// @returns The destination color.
		private System.Drawing.Color CalcDestColor(System.Drawing.Color sourceColor,
			System.Drawing.Color backgroundColor, double lightValue) {
			double sourceRed = (double)sourceColor.R / 255.0;
			double sourceGreen = (double)sourceColor.G / 255.0;
			double sourceBlue = (double)sourceColor.B / 255.0;
			double sourceAlpha = (double)sourceColor.A / 255.0;
			double backgroundRed = (double)backgroundColor.R / 255.0;
			double backgroundGreen = (double)backgroundColor.G / 255.0;
			double backgroundBlue = (double)backgroundColor.B / 255.0;

			// First, blend the source color to the background color using the alpha
			// of the source color.
			double red = Utils.LinearInterp(backgroundRed, sourceRed, sourceAlpha);
			double green = Utils.LinearInterp(backgroundGreen, sourceGreen, sourceAlpha);
			double blue = Utils.LinearInterp(backgroundBlue, sourceBlue, sourceAlpha);

			if (m_isLightEnabled) {

				// Now calculate the light color.
				double lightRed = lightValue * (double)m_lightColor.R / 255.0;
				double lightGreen = lightValue * (double)m_lightColor.G / 255.0;
				double lightBlue = lightValue * (double)m_lightColor.B / 255.0;

				// Apply the light color to the new color.
				red *= lightRed;
				green *= lightGreen;
				blue *= lightBlue;
			}

			// Clamp the color channels to the (0..1) range.
			red = (red < 0.0) ? 0.0 : red;
			red = (red > 1.0) ? 1.0 : red;
			green = (green < 0.0) ? 0.0 : green;
			green = (green > 1.0) ? 1.0 : green;
			blue = (blue < 0.0) ? 0.0 : blue;
			blue = (blue > 1.0) ? 1.0 : blue;

			// Rescale the color channels to the noise::uint8 (0..255) range and return
			// the new color.
			System.Drawing.Color newColor = System.Drawing.Color.FromArgb(
				(sourceColor.A > backgroundColor.A) ? sourceColor.A : backgroundColor.A,
				(byte)((int)(red * 255.0) & 0xff),
				(byte)((int)(green * 255.0) & 0xff),
				(byte)((int)(blue * 255.0) & 0xff));
			return newColor;
		}

		/// Calculates the intensity of the light given some elevation values.
		///
		/// @param center Elevation of the center point.
		/// @param left Elevation of the point directly left of the center
		/// point.
		/// @param right Elevation of the point directly right of the center
		/// point.
		/// @param down Elevation of the point directly below the center
		/// point.
		/// @param up Elevation of the point directly above the center point.
		///
		/// These values come directly from the noise map.
		private double CalcLightIntensity(double center, double left, double right, double down, double up) {
			// Recalculate the sine and cosine of the various light values if
			// necessary so it does not have to be calculated each time this method is
			// called.
			if (m_recalcLightValues) {
				m_cosAzimuth = Math.Cos(m_lightAzimuth * Utils.DegToRad);
				m_sinAzimuth = Math.Sin(m_lightAzimuth * Utils.DegToRad);
				m_cosElev = Math.Cos(m_lightElev * Utils.DegToRad);
				m_sinElev = Math.Sin(m_lightElev * Utils.DegToRad);
				m_recalcLightValues = false;
			}

			// Now do the lighting calculations.
			const double I_MAX = 1.0;
			double io = I_MAX * Math.Sqrt(2) * m_sinElev / 2.0;
			double ix = (I_MAX - io) * m_lightContrast * Math.Sqrt(2) * m_cosElev
			  * m_cosAzimuth;
			double iy = (I_MAX - io) * m_lightContrast * Math.Sqrt(2) * m_cosElev
			  * m_sinAzimuth;
			double intensity = (ix * (left - right) + iy * (down - up) + io);
			if (intensity < 0.0) {
				intensity = 0.0;
			}
			return intensity;
		}

		/// The cosine of the azimuth of the light source.
		private double m_cosAzimuth;

		/// The cosine of the elevation of the light source.
		private double m_cosElev;

		/// The color gradient used to specify the image colors.
		private GradientColor m_gradient;

		/// A flag specifying whether lighting is enabled.
		private bool m_isLightEnabled;

		/// A flag specifying whether wrapping is enabled.
		private bool m_isWrapEnabled;

		/// The azimuth of the light source, in degrees.
		private double m_lightAzimuth;

		/// The brightness of the light source.
		private double m_lightBrightness;

		/// The color of the light source.
		private System.Drawing.Color m_lightColor;

		/// The contrast between areas in light and areas in shadow.
		private double m_lightContrast;

		/// The elevation of the light source, in degrees.
		private double m_lightElev;

		/// The intensity of the light source.
		private double m_lightIntensity;

		/// A pointer to the background image.
		private Bitmap m_pBackgroundImage;

		/// A pointer to the source noise map.
		private NoiseMap m_pSourceNoiseMap;

		/// Used by the CalcLightIntensity() method to recalculate the light
		/// values only if the light parameters change.
		///
		/// When the light parameters change, this value is set to True.  When
		/// the CalcLightIntensity() method is called, this value is set to
		/// false.
		private bool m_recalcLightValues;

		/// The sine of the azimuth of the light source.
		private double m_sinAzimuth;

		/// The sine of the elevation of the light source.
		private double m_sinElev;

	}
}
